using System.Diagnostics;

namespace SPI.AgentServer.Middleware;

/// <summary>
/// 请求超时中间件 - 防止请求长时间卡住
/// </summary>
public class RequestTimeoutMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RequestTimeoutMiddleware> _logger;
    private readonly TimeSpan _timeout;

    public RequestTimeoutMiddleware(
        RequestDelegate next, 
        ILogger<RequestTimeoutMiddleware> logger,
        IConfiguration configuration)
    {
        _next = next;
        _logger = logger;
        _timeout = TimeSpan.FromSeconds(configuration.GetValue<int>("RequestTimeout", 300)); // 默认5分钟
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var stopwatch = Stopwatch.StartNew();
        var requestId = Guid.NewGuid().ToString("N")[..8];
        
        // 添加请求ID到响应头
        context.Response.Headers.Append("X-Request-ID", requestId);
        
        _logger.LogInformation("🔵 请求开始 [{RequestId}] {Method} {Path}", 
            requestId, context.Request.Method, context.Request.Path);

        using var cts = CancellationTokenSource.CreateLinkedTokenSource(context.RequestAborted);
        cts.CancelAfter(_timeout);

        try
        {
            await _next(context);
            
            stopwatch.Stop();
            _logger.LogInformation("🟢 请求完成 [{RequestId}] {StatusCode} 耗时:{Duration}ms", 
                requestId, context.Response.StatusCode, stopwatch.ElapsedMilliseconds);
        }
        catch (OperationCanceledException) when (cts.Token.IsCancellationRequested)
        {
            stopwatch.Stop();
            _logger.LogWarning("⏱️ 请求超时 [{RequestId}] {Method} {Path} 超过{Timeout}秒", 
                requestId, context.Request.Method, context.Request.Path, _timeout.TotalSeconds);
            
            if (!context.Response.HasStarted)
            {
                context.Response.StatusCode = 504; // Gateway Timeout
                await context.Response.WriteAsJsonAsync(new
                {
                    success = false,
                    error = "请求超时",
                    timeout = $"{_timeout.TotalSeconds}秒",
                    requestId = requestId
                });
            }
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            _logger.LogError(ex, "🔴 请求异常 [{RequestId}] {Method} {Path} 耗时:{Duration}ms", 
                requestId, context.Request.Method, context.Request.Path, stopwatch.ElapsedMilliseconds);
            throw;
        }
    }
}

/// <summary>
/// 请求超时中间件扩展方法
/// </summary>
public static class RequestTimeoutMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestTimeout(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestTimeoutMiddleware>();
    }
}

